from typing import List
from datetime import datetime

from sqlalchemy.exc import OperationalError
from sqlalchemy.orm import Session
from sqlalchemy.engine.base import Engine
import psycopg2
from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT

import settings
from scraper.utils import ProductData, ReviewData, PointsOfSaleData
from .models import Product, Review, PointsOfSale


def create_database(engine) -> None:
    """ Создаем базу данных если ее не существует """

    try:
        engine.connect()
    except OperationalError:
        connection = psycopg2.connect(
            user=settings.USERNAME_DB,
            password=settings.USER_PASSWORD_DB
        )
        connection.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)

        with connection.cursor() as cursor:
            cursor.execute('CREATE DATABASE scraper_vkusvill;')


def add_product_reviews(
    product: Product,
    list_of_reviews: List[ReviewData]
) -> None:
    """ Добавляем отзывы к продукту """

    for review in list_of_reviews:
        new_reviews = Review(**review)
        product.reviews.append(new_reviews)


def add_points_of_sale_to_product(
    session,
    product: Product,
    list_of_points_of_sale: List[str]
) -> None:
    """ Добавляем точки продажи к продукту """

    for point_of_sale in list_of_points_of_sale:
        new_point_of_sale = PointsOfSale(
            address=point_of_sale,
            product=product
        )
        session.add(new_point_of_sale)
        session.commit()


def add_product_to_db(engine: Engine, product: ProductData) -> None:
    """ Добавляем новый продукт в базу данных """

    def check_product_to_add(product_link: str) -> bool:
        """ Проверяем нужно ли добавлять продукт """

        product = session.query(Product) \
                            .filter(Product.link==product_link) \
                            .first()

        if not product: return True

        product_add_date = product.date.strftime('%Y-%m-%d')
        current_date = datetime.now().strftime('%Y-%m-%d')
        dates_dont_match = product_add_date != current_date

        if product and dates_dont_match: return True
        else: return False


    # ВЫШЕ ОПРЕДЕЛЕНИЕ ФУНКЦИЙ

    with Session(autoflush=False, bind=engine) as session:

        if not check_product_to_add(product['information']['link']): return

        new_product = Product(
            **product['information'],
        )
        add_product_reviews(
            new_product,
            product['reviews']
        )
        add_points_of_sale_to_product(
            session,
            new_product,
            product['points_of_sale']['list_of_points_of_sale']
        )

        session.add(new_product)
        session.commit()
